using System;
using System.Collections.Generic;
using System.Linq;
using FITClub.Episode1.Controller;
using FITClub.TextureMenu;
using FITClub.Util;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;

namespace LProject.XNA.RemoteController
{
    public class TouchController : GameComponent
    {
        public Rectangle[] Regions { get; private set; }

        public Rectangle UpLeftRegion { get; private set; }

        public Rectangle UpRightRegion { get; private set; }

        private VirtualGamepadState vgstate;
        private TouchCollection touches;
        private IEnumerable<Vector2> positionsDown;

        Vector2 thumbstickThreshold;

        public bool ThumbstickHit { get; private set; }

        public Rectangle Thumbstick { get; private set; }

        public Rectangle ThumbstickBounds { get; private set; }

        public bool UseArrows { get; set; }

        public Rectangle ThumbstickDefault { get; private set; }

        private Vector2 lastThumbstickHit;

        public TouchController(Game game)
            : base(game)
        {
            this.Regions = new Rectangle[]{
                new Rectangle(300,0,200,150),
                 new Rectangle(0,150,250,150),
                  new Rectangle(300,300,200,150),
                   new Rectangle(550,150,250,150),
                    new Rectangle(600,320,150,150),
                    new Rectangle(50,320,150,150)
            };
            this.ThumbstickBounds = new Rectangle(0, 250, 130, 130);
            this.Thumbstick = new Rectangle(60, 330, 100, 100);
            this.ThumbstickDefault = this.Thumbstick;
            this.thumbstickThreshold = new Vector2(Thumbstick.Width / 6, Thumbstick.Width / 5);

            this.UpLeftRegion = new Rectangle(0, 0, 250, 120);
            this.UpRightRegion = new Rectangle(550, 0, 250, 120);

            this.Attack = new Rectangle(640, 360, 100, 100);
            this.Defence = new Rectangle(500, 360, 100, 100);

            var controllers = from item in this.Game.Components where item is TouchController select item;
            if (controllers.Count() > 0)
            {
                throw new InvalidOperationException("Cannot create duplicate touch controller");
            }
            this.vgstate = VirtualGamepadState.Default;

            if (TouchPanel.EnabledGestures != GestureType.Tap)
            {
                TouchPanel.EnabledGestures |= GestureType.Tap;
            }
            if (TouchPanel.EnabledGestures != GestureType.HorizontalDrag)
            {
                TouchPanel.EnabledGestures |= GestureType.HorizontalDrag;
            }
            if (TouchPanel.EnabledGestures != GestureType.VerticalDrag)
            {
                TouchPanel.EnabledGestures |= GestureType.VerticalDrag;
            }
            if (TouchPanel.EnabledGestures != GestureType.Pinch)
            {
                TouchPanel.EnabledGestures |= GestureType.Pinch;
            }
            this.positionsDown = new Vector2[0];
            this.UpdateOrder = int.MinValue + 100; /// reserve slots for OneTimeWorkItem
            this.Game.Components.Add(this);
        }

        public override void Update(GameTime gameTime)
        {
            vgstate = VirtualGamepadState.Default;
            touches = TouchPanel.GetState();
            positionsDown = from ts in touches where ts.State == TouchLocationState.Moved || ts.State == TouchLocationState.Pressed select ts.Position;

            if (this.UseArrows)
            {
                this.UpdateArrows();
            }
            else
            {
                vgstate[4] = RectangleHit(this.Attack);
                vgstate[5] = RectangleHit(this.Defence);

                this.UpdateThumbstick();
            }
        }

        private void UpdateArrows()
        {
            for (int i = 0; i < Regions.Length; i++)
            {
                vgstate[i] = RectangleHit(Regions[i]);
            }
            //// koniec nekonzistentneho stavu

            if (RectangleHit(this.UpLeftRegion))
            {
                vgstate[0] = true;
                vgstate[1] = true;
            }

            if (RectangleHit(this.UpRightRegion))
            {
                vgstate[0] = true;
                vgstate[3] = true;
            }
        }

        private void UpdateThumbstick()
        {
            Vector2 actualHit = Vector2.Zero;
            if (this.RectangleHit(this.Thumbstick, ref actualHit))
            {
                if (this.ThumbstickHit)
                {
                    var delta = actualHit - this.lastThumbstickHit;
                    if (this.ThumbstickBounds.ContainsCropped(delta + this.Thumbstick.LocationV2()))
                    {
                        this.Thumbstick = this.Thumbstick.OffsetXY(delta);
                    }
                }
                else
                {
                    this.ThumbstickHit = true;
                }

                this.vgstate[0] = (this.Thumbstick.Y <= this.ThumbstickDefault.Y - thumbstickThreshold.Y);
                this.vgstate[1] = (this.Thumbstick.X <= this.ThumbstickDefault.X - thumbstickThreshold.X);
                this.vgstate[2] = (this.Thumbstick.Y >= this.ThumbstickDefault.Y + thumbstickThreshold.Y);
                this.vgstate[3] = (this.Thumbstick.X >= this.ThumbstickDefault.X + thumbstickThreshold.X);

                this.lastThumbstickHit = actualHit;
            }
            else
            {
                this.Thumbstick = this.ThumbstickDefault;
                this.ThumbstickHit = false;
            }
        }

        public bool RectangleHit(Rectangle rect)
        {
            foreach (var item in positionsDown)
            {
                if (rect.ContainsRounded(item))
                {
                    return true;
                }
            }
            return false;
        }

        public bool RectangleHit(Rectangle rect, ref Vector2 hitpoint)
        {
            foreach (var item in positionsDown)
            {
                if (rect.ContainsRounded(item))
                {
                    hitpoint = item;
                    return true;
                }
            }
            return false;
        }

        public VirtualGamepadState GetState()
        {
            return this.vgstate;
        }

        public Rectangle Attack { get; private set; }

        public Rectangle Defence { get; private set; }
    }

}